/**
 * Copyright (C) 2009 Olafur Gauti Gudmundsson, Hjortur Stefan Olafsson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.gwt_control.client;

import com.google.gwt.dom.client.Style;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;

/**
 *
 * @author Olafur Gauti Gudmundsson
 */
public class Fader {

    private static final Fader singleInstance = new Fader();

    public static void fadeIn(Widget toAppear, int duration ) {
        opacity(toAppear, .0, 1.0, duration);
    }

    public static void fadeOut(Widget toDisappear, int duration ) {
        opacity(toDisappear, 1.0, .0, duration);
    }

    public static void opacity(Widget widget, double from, double to, int duration){
        int steps = duration/OpacityTimer.FREQ;
        OpacityTimer opacity = singleInstance.new OpacityTimer(widget, from, to, steps, to > from);
        opacity.schedule(100);
    }

    protected static native void setMozOpacity(Style style, String opacity) /*-{
      style["-moz-opacity"] = opacity;
    }-*/;

    protected static native void setKhtmlOpacity(Style style, String opacity) /*-{
      style["-khtml-opacity"] = opacity;
    }-*/;

    private abstract class GUITimer extends Timer {

        public static final int FREQ = 100;
        private int curStep;
        private Element element;
        private int steps;
        protected boolean countUp;

        public GUITimer( Widget widget, int steps, boolean countUp ) {
            this.element = widget.getElement();
            this.steps = steps;
            this.countUp = countUp;
            if ( countUp ) {
                curStep = 0;
            } else {
                curStep = steps;
            }
        }

        protected abstract void doStep(double pct);

        protected abstract void doFinished();

        public Element getElement() {
            return element;
        }

        public int getSteps(){
            return steps;
        }

        @Override
        public void run() {
            doStep(curStep/(double)steps);
            if ( countUp ) {
                curStep++;
                if(curStep>steps){
                    cancel();
                    doFinished();
                } else {
                    schedule(FREQ);
                }
            } else {
                curStep--;
                if ( curStep < 0 ) {
                    cancel();
                    doFinished();
                } else {
                    schedule(FREQ);
                }
            }
        }
    }

    private class OpacityTimer extends GUITimer {

        private double diff;
        private double start;
        private Widget widget;

        public OpacityTimer( Widget widget, double from, double to, int steps, boolean countUp ) {
            super(widget, steps, countUp);
            this.widget = widget;

            if ( countUp ) {
                this.start = from;
                this.diff=to-from;
                setOpacity(0.0);
                widget.setVisible(true);
            } else {
                this.start = to;
                this.diff=from-to;
            }
        }

        private void setOpacity( double opacity ) {
            String ieStr="alpha(opacity="+(int)(opacity*100)+")";
            DOM.setStyleAttribute(getElement(), "filter", ieStr);
            setMozOpacity(getElement().getStyle(), opacity + "");
            //DOM.setStyleAttribute(getElement(), "-moz-opacity", opacity + "");
            DOM.setStyleAttribute(getElement(), "opacity", opacity + "");
            setKhtmlOpacity(getElement().getStyle(), opacity + "");
            //DOM.setStyleAttribute(getElement(), "-khtml-opacity", opacity +"")
        }

        @Override
        protected void doStep( double pct ) {
            double cur = pct * diff + start;
            if ( cur > 0 ) {
                setOpacity(cur);
            } else {
                setOpacity(0.0);
            }
        }

        @Override
        protected void doFinished() {
            if ( !countUp ) {
                widget.setVisible(false);
            }
        }
    }
}
